#ifndef Serialization_H_
#define Serialization_H_

/*

    C++实现二进制序列化/反序列化

    摘自 "https://www.cnblogs.com/Keeping-Fit/p/14952742.html"  [C++实现二进制序列化/反序列化]
    
    背景
        涉及对象传输或存储时，均需要序列化的参与，将对象转为连续的二进制数据后才能进行传输或存储，需要还原对象时，
        通过反序列化逆向处理二进制数据遍能得到原对象

        - 这里的对象是一种广泛的概念，往大了说就是一段有意义的内存

    实现
        - 实现过程中主要使用模板应对各种类型，特化+宏应对基础数据类型，逐层处理应对STL容器嵌套情况
        - C++语言本身不带反射，自定义结构需继承接口类Serializable，并实现相应接口
        - 实现时使用了std::move()进行构造与赋值，自定义结构最好实现自己的移动构造函数与移动赋值函数
        - 获取序列化buffer时，先计算序列化目标在序列化后的总字节数，一次性申请足够内存
        - 获取序列化buffer时，返回的buffer之前藏了序列化目标的总字节数，藏东西这招跟redis学的
        - 藏的目标总字节数目的用于，反序列化前简单判断待反序列化buffer是否有效
        - 未支持指针类型，传递错误类型的指针(强转目标类型与实际类型不符合)会导致内存错误，序列化过程中没法判断类型是否正确
        - 未支持C风格字符串，C风格字符串以0结尾，非二进制安全
        - 需要序列化一段连续内存时，构造std::string后传入
        - 反序列化时，调用者需自行保证，待反序列化buffer的原始类型与目标类型一致，代码不能识别出类型差异与结构改变
        - 使用方式 申请序列化buffer->序列化->三方库压缩->三方库加密->传输/落盘->接收/读取->三方库解密->三方库解压->简单检查->反序列化->释放buffer
        - 序列化后的数据格式如下
            . 先写入对象序列化后总长度，后面才接着写入对象序列化数据
                .. 对象是基础类型则直接写入数据
                .. 对象是STL容器先写入元素个数，再写入每个元素序列化数据
                     如果元素是std::pairl类型，则先写入序列化Key，再写入序列化Value
                .. 对象是自定义结构，则需用户定义数据格式
        总体结构：

*/

#include <map>
#include <set>
#include <list>
#include <string>
#include <vector>
#include <memory>
#include <string.h>

//基础数据长度计算
#define BASIC_DATA_LENGTH(BasicType)              \
    static unsigned Length(const BasicType &elem) \
    {                                             \
        return sizeof(elem);                      \
    }

//申请用于序列化的buffer         总格式    |数据总长度|数据|
#define MAKE_BUFFER(uLen)                              \
    {                                                  \
        char *pBuffer = new char[uLen + sizeof(LEN)];  \
        if (nullptr == pBuffer)                        \
        {                                              \
            return nullptr;                            \
        }                                              \
        *reinterpret_cast<LEN *const>(pBuffer) = uLen; \
        return pBuffer + sizeof(LEN);                  \
    }

//基础数据序列化buffer获取
#define BASIC_DATA_GET_BUFFER(BasicType)                \
                                                        \
    static char *const GetBuffer(const BasicType &elem) \
    {                                                   \
        LEN uLen = sizeof(elem);                        \
        MAKE_BUFFER(uLen);                              \
    }

//基础数据序列化主体
#define BASIC_DATA_SERIALIZE(BasicType)                                   \
                                                                          \
    static unsigned Serialize(const BasicType &elem, char *const pBuffer) \
    {                                                                     \
        ::memcpy(pBuffer, &elem, sizeof(BasicType));                      \
        return sizeof(BasicType);                                         \
    }

//基础数据反序列化主体
#define BASIC_DATA_UNSERIALIZE(BasicType)                                   \
                                                                            \
    static unsigned UnSerialize(const char *const pBuffer, BasicType &elem) \
    {                                                                       \
        ::memcpy(&elem, pBuffer, sizeof(BasicType));                        \
        return sizeof(BasicType);                                           \
    }

namespace Serialization
{
    //存放长度信息类型
    using LEN = unsigned;

    //自定义结构序列化基类
    class Serializable
    {
    public:
        virtual unsigned Length() const = 0;
        virtual unsigned Serialize(char *const pBuffer) const = 0;
        virtual unsigned UnSerialize(const char *const pBuffer) = 0;
        virtual ~Serializable(){};
    };

    /*
        前项声明部分，STL容器嵌套编译问题
    */
    template <typename Elem>
    unsigned Length(const std::list<Elem> &list);
    template <typename Key, typename Value>
    unsigned Length(const std::map<Key, Value> &map);
    template <typename Elem>
    unsigned Length(const std::vector<Elem> &vec);
    template <typename Elem>
    unsigned Length(const std::set<Elem> &set);

    template <typename Elem>
    char *const GetBuffer(const std::list<Elem> &list);
    template <typename Key, typename Value>
    char *const GetBuffer(const std::map<Key, Value> &map);
    template <typename Elem>
    char *const GetBuffer(const std::vector<Elem> &vec);
    template <typename Elem>
    char *const GetBuffer(const std::set<Elem> &set);

    template <typename Elem>
    unsigned Serialize(const std::list<Elem> &list, char *const pBuffer);
    template <typename Key, typename Value>
    unsigned Serialize(const std::map<Key, Value> &map, char *const pBuffer);
    template <typename Elem>
    unsigned Serialize(const std::vector<Elem> &vec, char *const pBuffer);
    template <typename Elem>
    unsigned Serialize(const std::set<Elem> &set, char *const pBuffer);

    template <typename Elem>
    unsigned UnSerialize(const char *pBuffer, std::list<Elem> &list);
    template <typename Key, typename Value>
    unsigned UnSerialize(const char *pBuffer, std::map<Key, Value> &map);
    template <typename Elem>
    unsigned UnSerialize(const char *pBuffer, std::vector<Elem> &vec);
    template <typename Elem>
    unsigned UnSerialize(const char *pBuffer, std::set<Elem> &set);

    /*
        长度计算部分
        得到数据长度
    */
    template <typename Elem>
    static unsigned Length(const Elem &elem)
    {
        return elem.Length();
    }

    BASIC_DATA_LENGTH(char)
    BASIC_DATA_LENGTH(short)
    BASIC_DATA_LENGTH(int)
    BASIC_DATA_LENGTH(float)
    BASIC_DATA_LENGTH(long)
    BASIC_DATA_LENGTH(double)
    BASIC_DATA_LENGTH(long long)
    BASIC_DATA_LENGTH(unsigned char)
    BASIC_DATA_LENGTH(unsigned short)
    BASIC_DATA_LENGTH(unsigned int)
    BASIC_DATA_LENGTH(unsigned long)
    BASIC_DATA_LENGTH(unsigned long long)

    static unsigned Length(const std::string &str)
    {
        return sizeof(LEN) + static_cast<unsigned>(str.size()); //容器对象 格式 |元素个数|数据|
    }

    template <typename Elem>
    static unsigned Length(const std::list<Elem> &list)
    {
        LEN uLen = 0;
        for (const auto &elem : list)
        {
            uLen += Length(elem);
        }
        return sizeof(LEN) + uLen;
    }

    template <typename Key, typename Value>
    static unsigned Length(const std::map<Key, Value> &map)
    {
        LEN uLen = 0;
        for (const auto &elem : map)
        {
            uLen += Length(elem.first);
            uLen += Length(elem.second);
        }
        return sizeof(LEN) + uLen;
    }

    template <typename Elem>
    static unsigned Length(const std::vector<Elem> &vec)
    {
        LEN uLen = 0;
        for (const auto &elem : vec)
        {
            uLen += Length(elem);
        }
        return sizeof(LEN) + uLen;
    }

    template <typename Elem>
    static unsigned Length(const std::set<Elem> &set)
    {
        LEN uLen = 0;
        for (const auto &elem : set)
        {
            uLen += Length(elem);
        }
        return sizeof(LEN) + uLen;
    }

    /*
        buffer申请、释放部分
        一次性申请足够内存
    */
    template <typename Elem>
    static char *const GetBuffer(const Elem &elem)
    {
        LEN uLen = elem.Length();
        MAKE_BUFFER(uLen);
    }

    BASIC_DATA_GET_BUFFER(char)
    BASIC_DATA_GET_BUFFER(short)
    BASIC_DATA_GET_BUFFER(int)
    BASIC_DATA_GET_BUFFER(float)
    BASIC_DATA_GET_BUFFER(long)
    BASIC_DATA_GET_BUFFER(double)
    BASIC_DATA_GET_BUFFER(long long)
    BASIC_DATA_GET_BUFFER(unsigned char)
    BASIC_DATA_GET_BUFFER(unsigned short)
    BASIC_DATA_GET_BUFFER(unsigned int)
    BASIC_DATA_GET_BUFFER(unsigned long)
    BASIC_DATA_GET_BUFFER(unsigned long long)

    static char *const GetBuffer(const std::string &str)
    {
        LEN uLen = Length(str);
        MAKE_BUFFER(uLen);
    }

    template <typename Elem>
    static char *const GetBuffer(const std::list<Elem> &list)
    {
        LEN uLen = Length(list);
        MAKE_BUFFER(uLen);
    }

    template <typename Key, typename Value>
    static char *const GetBuffer(const std::map<Key, Value> &map)
    {
        LEN uLen = Length(map);
        MAKE_BUFFER(uLen);
    }

    template <typename Elem>
    static char *const GetBuffer(const std::vector<Elem> &vec)
    {
        LEN uLen = Length(vec);
        MAKE_BUFFER(uLen);
    }

    template <typename Elem>
    static char *const GetBuffer(const std::set<Elem> &set)
    {
        LEN uLen = Length(set);
        MAKE_BUFFER(uLen);
    }

    static void ReleaseBuffer(char *const pBuffer)
    {
        delete[](pBuffer - sizeof(LEN));
    }

    /*
        序列化部分
    */
    template <typename Elem>
    static unsigned Serialize(const Elem &elem, char *const pBuffer)
    {
        return elem.Serialize(pBuffer);
    }

    BASIC_DATA_SERIALIZE(char)
    BASIC_DATA_SERIALIZE(short)
    BASIC_DATA_SERIALIZE(int)
    BASIC_DATA_SERIALIZE(float)
    BASIC_DATA_SERIALIZE(long)
    BASIC_DATA_SERIALIZE(double)
    BASIC_DATA_SERIALIZE(long long)
    BASIC_DATA_SERIALIZE(unsigned char)
    BASIC_DATA_SERIALIZE(unsigned short)
    BASIC_DATA_SERIALIZE(unsigned int)
    BASIC_DATA_SERIALIZE(unsigned long)
    BASIC_DATA_SERIALIZE(unsigned long long)

    static unsigned Serialize(const std::string &str, char *const pBuffer)
    {
        *reinterpret_cast<LEN *const>(pBuffer) = static_cast<LEN>(str.size()); //元素个数
        ::memcpy(pBuffer + sizeof(LEN), str.data(), str.size());               //数据
        return static_cast<unsigned>(str.size()) + sizeof(LEN);
    }

    template <typename Elem>
    static unsigned Serialize(const std::list<Elem> &list, char *const pBuffer)
    {
        unsigned uPos = sizeof(LEN);
        *reinterpret_cast<LEN *const>(pBuffer) = static_cast<LEN>(list.size()); //元素个数
        for (const auto &elem : list)
        {
            uPos += Serialize(elem, pBuffer + uPos);
        }
        return uPos;
    }

    template <typename Key, typename Value>
    static unsigned Serialize(const std::map<Key, Value> &map, char *const pBuffer)
    {
        unsigned uPos = sizeof(LEN);
        *reinterpret_cast<LEN *const>(pBuffer) = static_cast<LEN>(map.size()); //元素个数
        for (const auto &elem : map)
        {
            uPos += Serialize(elem.first, pBuffer + uPos);
            uPos += Serialize(elem.second, pBuffer + uPos);
        }
        return uPos;
    }

    template <typename Elem>
    static unsigned Serialize(const std::vector<Elem> &vec, char *const pBuffer)
    {
        unsigned uPos = sizeof(LEN);
        *reinterpret_cast<LEN *const>(pBuffer) = static_cast<LEN>(vec.size()); //元素个数
        for (const auto &elem : vec)
        {
            uPos += Serialize(elem, pBuffer + uPos);
        }
        return uPos;
    }

    template <typename Elem>
    static unsigned Serialize(const std::set<Elem> &set, char *const pBuffer)
    {
        unsigned uPos = sizeof(LEN);
        *reinterpret_cast<LEN *const>(pBuffer) = static_cast<LEN>(set.size()); //元素个数
        for (const auto &elem : set)
        {
            uPos += Serialize(elem, pBuffer + uPos);
        }
        return uPos;
    }

    /*
        检查反序列化之前的buffer
        BufferLen指包含数据总长度在内的长度，即从硬盘上读取并解压缩后的整个buffer长度
    */
    static int CheckLength(const char *const pBuffer, int BufferLen)
    {
        if (*reinterpret_cast<const LEN *const>(pBuffer - sizeof(LEN)) + sizeof(LEN) != BufferLen)
        {
            return 0;
        }
        return 1;
    }

    /*
        反序列化部分
    */
    template <typename Elem>
    static unsigned UnSerialize(const char *pBuffer, Elem &elem)
    {
        return elem.UnSerialize(pBuffer);
    }

    BASIC_DATA_UNSERIALIZE(char)
    BASIC_DATA_UNSERIALIZE(short)
    BASIC_DATA_UNSERIALIZE(int)
    BASIC_DATA_UNSERIALIZE(float)
    BASIC_DATA_UNSERIALIZE(long)
    BASIC_DATA_UNSERIALIZE(double)
    BASIC_DATA_UNSERIALIZE(long long)
    BASIC_DATA_UNSERIALIZE(unsigned char)
    BASIC_DATA_UNSERIALIZE(unsigned short)
    BASIC_DATA_UNSERIALIZE(unsigned int)
    BASIC_DATA_UNSERIALIZE(unsigned long)
    BASIC_DATA_UNSERIALIZE(unsigned long long)

    static unsigned UnSerialize(const char *pBuffer, std::string &str)
    {
        LEN uLen = *reinterpret_cast<const LEN *>(pBuffer);
        std::string strTemp(pBuffer + sizeof(LEN), uLen);
        str = std::move(strTemp);
        return uLen + sizeof(LEN);
    }

    template <typename Elem>
    static unsigned UnSerialize(const char *pBuffer, std::list<Elem> &list)
    {
        LEN uLen = *reinterpret_cast<const LEN *>(pBuffer);
        unsigned uPos = sizeof(LEN);
        for (LEN i = 0; i < uLen; i++)
        {
            Elem elem;
            uPos += UnSerialize(pBuffer + uPos, elem);
            list.push_back(std::move(elem));
        }
        return uPos;
    }

    template <typename Key, typename Value>
    static unsigned UnSerialize(const char *pBuffer, std::map<Key, Value> &map)
    {
        LEN uLen = *reinterpret_cast<const LEN *>(pBuffer);
        unsigned uPos = sizeof(LEN);
        for (LEN i = 0; i < uLen; i++)
        {
            Key key;
            Value val;
            uPos += UnSerialize(pBuffer + uPos, key);
            uPos += UnSerialize(pBuffer + uPos, val);
            map.insert(std::make_pair(std::move(key), std::move(val)));
        }
        return uPos;
    }

    template <typename Elem>
    static unsigned UnSerialize(const char *pBuffer, std::vector<Elem> &vec)
    {
        LEN uLen = *reinterpret_cast<const LEN *>(pBuffer);
        vec.resize(uLen);
        unsigned uPos = sizeof(LEN);
        for (LEN i = 0; i < uLen; i++)
        {
            Elem elem;
            uPos += UnSerialize(pBuffer + uPos, elem);
            vec[i] = std::move(elem);
        }
        return uPos;
    }

    template <typename Elem>
    static unsigned UnSerialize(const char *pBuffer, std::set<Elem> &set)
    {
        LEN uLen = *reinterpret_cast<const LEN *>(pBuffer);
        unsigned uPos = sizeof(LEN);
        for (LEN i = 0; i < uLen; i++)
        {
            Elem elem;
            uPos += UnSerialize(pBuffer + uPos, elem);
            set.emplace(std::move(elem));
        }
        return uPos;
    }

}

#endif

